﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Sino.CapacityCloud.Infrastructure.Services
{

    public abstract class BackgroundWorker
        : IBackgroundWorker
    {

        protected readonly ILogger _logger;

        protected Task _dispatchThread;
        protected CancellationTokenSource _cancellationTokenSource;

        public virtual bool IsRunning
        {
            get
            {
                return this._dispatchThread != null && this._dispatchThread.Status == TaskStatus.Running;
            }
        }

        protected BackgroundWorker(ILoggerFactory loggerFactory)
        {
            this._logger = loggerFactory.CreateLogger(this.GetType().FullName);
        }

        public virtual void Start()
        {
            if (this.IsRunning)
            {
                return;
            }
            this._cancellationTokenSource = new CancellationTokenSource();
            this._dispatchThread = this.ThreadWorker(this._cancellationTokenSource.Token);
            //{
            //    IsBackground = true,
            //    Name = $"{this.GetType().Name}-Thread-{this._dispatchThread.ManagedThreadId}"
            //};
            //this._dispatchThread.Start(this._cancellationTokenSource.Token);
        }

        public virtual void Stop(int timeout = 2000)
        {
            Task.WaitAny(Task.Run(() =>
            {
                this._cancellationTokenSource.Cancel();
                while (this.IsRunning)
                {
                    Task.Delay(500);
                }
            }), Task.Delay(timeout));
        }

        protected virtual async Task ThreadWorker(object userObject)
        {
            this._logger.LogInformation($"Background worker {this.GetType().FullName} has been started.");
            var token = (CancellationToken)userObject;
            while (!token.IsCancellationRequested && await this.Process())
            {
            }
        }

        protected abstract Task<bool> Process();

    }

}